#pragma once

#include "Sparse/CAMSparse.h"
#include "MatrixTemplates.h"
#include "AMD/Include/amd.h"
//#include "LDL/Include/ldl.h"

class CCAMSolvers
{
public:
	CCAMSolvers(void);
	~CCAMSolvers(void);

	struct stSolversParam
	{
		stSolversParam():Status(0)/*,IDSolver(0)*/ {};
		long Status;
		//long IDSolver;
		std::vector<std::wstring> vmsg;
		std::wstring NameSolver;
	};

	// solve A * x = b; x = A/b 
	bool SparseSolve (CCAMSparse *A, cm::Matrix1D_double *b, cm::Matrix1D_double *x,   stSolversParam* param);


	bool LDLSolver (CCAMSparse *A, cm::Matrix1D_double *b, cm::Matrix1D_double *x,   stSolversParam* param);

	/* ========================================================================== */
/* === ldl_perm: permute a vector, x=Pb ===================================== */
/* ========================================================================== */

void ldl_l_perm //LDL_perm
(
    long n,		/* size of X, B, and P */
    double X [ ],	/* output of size n. */
    double B [ ],	/* input of size n. */
    long P [ ]	/* input permutation array of size n. */
);
/* ========================================================================== */
/* === ldl_symbolic ========================================================= */
/* ========================================================================== */

/* The input to this routine is a sparse matrix A, stored in column form, and
 * an optional permutation P.  The output is the elimination tree
 * and the number of nonzeros in each column of L.  Parent [i] = k if k is the
 * parent of i in the tree.  The Parent array is required by ldl_numeric.
 * Lnz [k] gives the number of nonzeros in the kth column of L, excluding the
 * diagonal.
 *
 * One workspace vector (Flag) of size n is required.
 *
 * If P is NULL, then it is ignored.  The factorization will be LDL' = A.
 * Pinv is not computed.  In this case, neither P nor Pinv are required by
 * ldl_numeric.
 *
 * If P is not NULL, then it is assumed to be a valid permutation.  If
 * row and column j of A is the kth pivot, the P [k] = j.  The factorization
 * will be LDL' = PAP', or A (p,p) in MATLAB notation.  The inverse permutation
 * Pinv is computed, where Pinv [j] = k if P [k] = j.  In this case, both P
 * and Pinv are required as inputs to ldl_numeric.
 *
 * The floating-point operation count of the subsequent call to ldl_numeric
 * is not returned, but could be computed after ldl_symbolic is done.  It is
 * the sum of (Lnz [k]) * (Lnz [k] + 2) for k = 0 to n-1.
 */

void ldl_l_symbolic
(
    long n,		/* A and L are n-by-n, where n >= 0 */
    long Ap [ ],	/* input of size n+1, not modified */
    long Ai [ ],	/* input of size nz=Ap[n], not modified */
    long Lp [ ],	/* output of size n+1, not defined on input */
    long Parent [ ],	/* output of size n, not defined on input */
    long Lnz [ ],	/* output of size n, not defined on input */
    long Flag [ ],	/* workspace of size n, not defn. on input or output */
    long P [ ],	/* optional input of size n */
    long Pinv [ ]	/* optional output of size n (used if P is not NULL) */
);
/* ========================================================================== */
/* === ldl_numeric ========================================================== */
/* ========================================================================== */

/* Given a sparse matrix A (the arguments n, Ap, Ai, and Ax) and its symbolic
 * analysis (Lp and Parent, and optionally P and Pinv), compute the numeric LDL'
 * factorization of A or PAP'.  The outputs of this routine are arguments Li,
 * Lx, and D.  It also requires three size-n workspaces (Y, Pattern, and Flag).
 */
long ldl_l_numeric	/* returns n if successful, k if D (k,k) is zero */
(
    long n,		/* A and L are n-by-n, where n >= 0 */
    long Ap [ ],	/* input of size n+1, not modified */
    long Ai [ ],	/* input of size nz=Ap[n], not modified */
    double Ax [ ],	/* input of size nz=Ap[n], not modified */
    long Lp [ ],	/* input of size n+1, not modified */
    long Parent [ ],	/* input of size n, not modified */
    long Lnz [ ],	/* output of size n, not defn. on input */
    long Li [ ],	/* output of size lnz=Lp[n], not defined on input */
    double Lx [ ],	/* output of size lnz=Lp[n], not defined on input */
    double D [ ],	/* output of size n, not defined on input */
    double Y [ ],	/* workspace of size n, not defn. on input or output */
    long Pattern [ ],/* workspace of size n, not defn. on input or output */
    long Flag [ ],	/* workspace of size n, not defn. on input or output */
    long P [ ],	/* optional input of size n */
    long Pinv [ ]	/* optional input of size n */
);

/* ========================================================================== */
/* === ldl_lsolve:  solve Lx=b ============================================== */
/* ========================================================================== */

void ldl_l_lsolve
(
    long n,		/* L is n-by-n, where n >= 0 */
    double X [ ],	/* size n.  right-hand-side on input, soln. on output */
    long Lp [ ],	/* input of size n+1, not modified */
    long Li [ ],	/* input of size lnz=Lp[n], not modified */
    double Lx [ ]	/* input of size lnz=Lp[n], not modified */
);

/* ========================================================================== */
/* === ldl_dsolve:  solve Dx=b ============================================== */
/* ========================================================================== */

void ldl_l_dsolve
(
    long n,		/* D is n-by-n, where n >= 0 */
    double X [ ],	/* size n.  right-hand-side on input, soln. on output */
    double D [ ]	/* input of size n, not modified */
);

/* ========================================================================== */
/* === ldl_ltsolve: solve L'x=b  ============================================ */
/* ========================================================================== */

void ldl_l_ltsolve
(
    long n,		/* L is n-by-n, where n >= 0 */
    double X [ ],	/* size n.  right-hand-side on input, soln. on output */
    long Lp [ ],	/* input of size n+1, not modified */
    long Li [ ],	/* input of size lnz=Lp[n], not modified */
    double Lx [ ]	/* input of size lnz=Lp[n], not modified */
);

void ldl_l_permt
(
    long n,		/* size of X, B, and P */
    double X [ ],	/* output of size n. */
    double B [ ],	/* input of size n. */
    long P [ ]	/* input permutation array of size n. */
);

};

